package classpath

import (
	"os"
	"path/filepath"
)

type Classpath struct {
	// 启动类路径
	bootClasspath Entry
	// 扩展类路径
	extClasspath Entry
	//用户类路径
	userClasspath Entry
}

/**
解析命令行参数中的jre路径和-cp或者-classpath指定的用户类路径
返回一个ClassPath的指针，这个结构体中包含了从启动类路径，扩展类路径，以及用户类路径下查找class文件的操作
 */
func Parse(jreOption string, cpOption string) *Classpath {
	cp := &Classpath{}
	// 启动类路径和扩展类路径，由-Xjre参数指定，如果没有设置-Xjre参数，则默认分别为环境变量JAVA_HOME下的jre目录和ext/jre目录
	cp.parseBootAndExtClasspath(jreOption)
	// 用户类路径，由-cp或-classpath参数指定，如果没指定，默认为当前目录
	cp.parseUserClasspath(cpOption)
	return cp
}

// 启动类路径和扩展类路径只找jar包中的文件
func (self *Classpath) parseBootAndExtClasspath(jreOption string) {
	// 获取jre目录
	jreDIr := getJreDir(jreOption)
	// 启动类路径，带*号，使用通配符进行搜索
	// 获取jrelib目录，jre/lib/*
	jreLibPath := filepath.Join(jreDIr, "lib", "*")
	self.bootClasspath = newWildcardEntry(jreLibPath)
	// 扩展类路径
	// jre/lib/ext/*
	jreExtPath := filepath.Join(jreDIr, "lib", "ext", "*")
	self.extClasspath = newWildcardEntry(jreExtPath)

}

// 获取jre目录
func getJreDir(jreOption string) string {
	// 指定了-Xjre参数的值，则使用指定的值
	if jreOption != "" && exists(jreOption) {
		return jreOption
	}
	if exists("./jre") {
		// 如果当前路径下存在jre文件夹，则使用当前路径下的jre目录
		return "./jre"
	}
	// 都没有，使用JAVA_HOME环境变量下的jre目录
	if jh := os.Getenv("JAVA_HOME"); jh != "" {
		return filepath.Join(jh, "jre")
	}
	panic("can not find jre folder")
}

func exists(path string) bool {
	if _, err := os.Stat(path); err != nil {
		if os.IsNotExist(err) {
			return false
		}
	}
	return true
}

// 用户类路径允许查找文件夹，jar包等文件
func (self *Classpath) parseUserClasspath(cpOption string) {
	if cpOption == "" {
		cpOption = "."
	}
	self.userClasspath = newEntry(cpOption)
}

/**
读取class文件内的数据，以字节数组返回
*/
func (self *Classpath) ReadClass(classname string) ([]byte, Entry, error) {
	// 加上.class后缀
	classname = classname + ".class"
	// 启动类路径下找到了，直接返回
	if data, entry, err := self.bootClasspath.ReadClass(classname); err == nil {
		return data, entry, err
	}
	// 启动类路径没找到，但是扩展类路径找到了，返回
	if data, entry, err := self.extClasspath.ReadClass(classname); err == nil {
		return data, entry, err
	}
	// 都没有，去用户类路径下寻找。还没找到就报错
	return self.userClasspath.ReadClass(classname)
}


func (self *Classpath) String() string {
	return self.userClasspath.String()
}
